/*****************************************************************************/
/* DC Motor control using PWM timer/output compare pin for PWM control       */
/*                                                                           */
/* Copyright (C) 2013 Laszlo Arvai                                           */
/* All rights reserved.                                                      */
/*                                                                           */
/* This software may be modified and distributed under the terms             */
/* of the BSD license.  See the LICENSE file for details.                    */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Includes
#include "stm32f30x.h"
#include <drvServo.h>
#include <krnlMemory.h>

///////////////////////////////////////////////////////////////////////////////
// Constants
#define DCMOTOR_TIMER_FREQUENCY 2000000
#define DCMOTOR_PWM_FREQUENCY 8000
#define DCMOTOR_TIMER_PRESCALER ( (SystemCoreClock / DCMOTOR_TIMER_FREQUENCY) - 1 );
#define DCMOTOR_TIMER_PERIOD (DCMOTOR_TIMER_FREQUENCY / DCMOTOR_PWM_FREQUENCY - 1)

///////////////////////////////////////////////////////////////////////////////
// Initialize Motor Control
void drvDCMotorInit(void)
{
	GPIO_InitTypeDef        GPIO_InitStructure;								//structure for GPIO setup
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;						//structure for TIM Time Base
	TIM_OCInitTypeDef				TIM_OCInitStructure;							//structure for TIM Output Compare
	NVIC_InitTypeDef				NVIC_InitStructure;								//structure for NVIC

	// init setup data
	MEM_ZERO(GPIO_InitStructure);
	MEM_ZERO(TIM_TimeBaseStructure);
	MEM_ZERO(TIM_OCInitStructure);
	MEM_ZERO(NVIC_InitStructure);

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);				//enable the AHB Peripheral Clock to use GPIOD
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);			//enable the TIM4 clock

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;								//configure PD12 in alternate function pushpull mode
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_2);			//connect the pin to the desired peripherals' Alternate Function (AF) - TIM3 (GPIO_AF_2)

	//configure timer to create PWM signal
	TIM_TimeBaseStructure.TIM_Prescaler = DCMOTOR_TIMER_PRESCALER;
	TIM_TimeBaseStructure.TIM_Period = DCMOTOR_TIMER_PERIOD;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;					//PWM mode configuration
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OC1Init(TIM4, &TIM_OCInitStructure);

	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);

	/* Enable the TIM4 global Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;    //0 highest priority
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;           //1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	TIM_SetCompare1(TIM4, 128);															//set the default compare value to 1500us
	TIM_Cmd(TIM4, ENABLE);																		//enable TIM4
}

void TIM4_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
	{
    TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
	}
}
